#include "gtd_common.hpp"
#include "gtd_profiler.hpp"

NAMESPACE_BEG(gtd)

#if GTD_PROFILING

struct Profiler::Record
{
    Record(const char* name, Record* parent):
        name(name),
        parent(parent),
        begTime(0),
        samples(0),
        curTime(0),
        totTime(0)
    {
        if(parent != NULL)
        {
            parent->children.push_back(this);
        }
    }

    void reset()
    {
        if(begTime > 0)
        {
            ++samples;
        }
        curTime = 0;
        begTime = 0;
        for(size_t i = 0; i < children.size(); ++i)
        {
            children[i]->reset();
        }
    }

    void print(std::ostream& os, const std::string& curIndent)
    {
        os << std::left << std::fixed;
        os << ' ' << std::setw(7) << curTime << " |";
        os << ' ' << std::setw(7) << totTime << " |";
        os << ' ' << std::setw(7) << std::setprecision(1) 
            << (samples ? totTime / double(samples) : 0.0) << " |";
        Uint32 parTime = parent != NULL ? parent->totTime : totTime;
        os << curIndent << std::setw(5) << std::setprecision(3) 
            << (parTime ? totTime / double(parTime) : 0) << " : " << name << std::endl;

        std::string childIndent = curIndent;
        childIndent.append("  ");
        for(size_t i = 0; i < children.size(); ++i)
        {
            children[i]->print(os, childIndent);
        }
    }

    const char* name;
    Record* parent;
    std::vector<Record*> children;
    Uint32 begTime;
    Uint32 samples;
    Uint32 curTime;
    Uint32 totTime;
};

std::map<std::string, Profiler::Record*> Profiler::records;
Profiler::Record* Profiler::current = NULL;
std::vector<Profiler::Record*> Profiler::roots;

Profiler::Sample::Sample(const char* name)
{
    std::map<std::string, Record*>::iterator it = records.find(name);
    if(it == records.end())
    {
        it = records.insert(std::make_pair(std::string(name), new Record(name, current))).first;
        if(current == NULL)
        {
            roots.push_back(it->second);
        }
    }
    record = it->second;
    current = record;

    record->begTime = SDL_GetTicks();
}

Profiler::Sample::~Sample()
{
    Uint32 time = SDL_GetTicks() - record->begTime;
    record->curTime += time;
    record->totTime += time;
    current = record->parent;
}

void Profiler::print(std::ostream& os)
{
    os << "_______________________________________________________" << std::endl;
    os << " Cur(ms) | Tot(ms) | Ave(ms) | Ave(%) : Name" << std::endl;
    os << "---------|---------|---------|-------------------------" << std::endl;
    for(std::vector<Record*>::iterator it = roots.begin(); it != roots.end(); ++it)
    {
        (*it)->print(os, " ");
    }
    os << "-------------------------------------------------------" << std::endl;
}

void Profiler::reset()
{
    for(std::vector<Record*>::iterator it = roots.begin(); it != roots.end(); ++it)
    {
        (*it)->reset();
    }
}

#endif

NAMESPACE_END(gtd)
